package test;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.DecoratingProxy;

/**
 * 基于 Spring AOP API 构建的一个非常简单的 Spring AOP的环境，用以源码剖析：JdkDynamicAopProxy。
 * 见：https://blog.csdn.net/f641385712/article/details/88952482
 *
 * @author ME
 * @date   2020/4/25
 */
public class SpringAopApiJDK {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory(new DemoImpl());
        // proxyFactory.addAdvice((MethodBeforeAdvice) (method, args1, target) -> {
        //     System.out.println("你被拦截了：方法名为：" + method.getName() + " 参数为--" + Arrays.asList(args1));
        // });
		MethodBeforeAdvice advice = new MethodBeforeAdvice() {
			@Override
			public void before(Method method, Object[] args1, Object target) throws Throwable {
				System.out.println("你被拦截了：方法名为：" + method.getName() + " 参数为--" + Arrays.asList(args1));
			}
		};
		proxyFactory.addAdvice(advice);

        IDemo demo = (IDemo) proxyFactory.getProxy();
        //你被拦截了：方法名为：hello 参数为--[]
        //this demo show
        demo.hello();

        System.out.println(proxyFactory.getTargetClass()); //class test.SpringAopApi$Demo
        System.out.println(proxyFactory.getTargetSource()); //SingletonTargetSource for target object [test.SpringAopApi$Demo@643b1d11]
        System.out.println(Arrays.asList(proxyFactory.getProxiedInterfaces())); //[interface test.SpringAopApi$DemoInterface]
        System.out.println(Arrays.asList(proxyFactory.getAdvisors()) + "\n"); //[org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [Pointcut.TRUE]; advice [test.SpringAopApi$$Lambda$2/1349414238@2ef5e5e3]]

        // 获取类型，看看是JDK代理还是cglib的
		System.out.println("\n测试 AOP 的内部接口");
        System.out.println(demo instanceof Proxy); //true  所有的 JDK代理都继承自 java.lang.reflect.Proxy
        System.out.println(demo instanceof SpringProxy); //true
        System.out.println(demo.getClass()); //class test.$Proxy0
        System.out.println(Proxy.isProxyClass(demo.getClass())); //true
        System.out.println(AopUtils.isCglibProxy(demo)); //false

        //测试 Advised接口、DecoratingProxy的内容
		System.out.println("\n测试 Advised接口、DecoratingProxy的内容");
        Advised advised = (Advised) demo;
        System.out.println(Arrays.asList(advised.getProxiedInterfaces())); //[interface test.SpringAopApi$DemoInterface]
        System.out.println(Arrays.asList(advised.getAdvisors())); //[org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [Pointcut.TRUE]; advice [test.SpringAopApi$$Lambda$2/1349414238@2ef5e5e3]]
        System.out.println(advised.isExposeProxy()); //false
        System.out.println(advised.isFrozen() + "\n"); //false

        // System.out.println(advised.removeAdvice(null));
        DecoratingProxy decoratingProxy = (DecoratingProxy) demo;
        System.out.println(decoratingProxy.getDecoratedClass() + "\n"); //class test.SpringAopApi$Demo

        System.out.println("-----------------------------------------------------");

        // Object的方法 ==== 所有的Object方法都不会被 AOP代理 这点需要注意
        System.out.println(demo.equals(new Object()));
        System.out.println(demo.hashCode());
        System.out.println(demo.getClass() + "\n");

        // 其余方法都没被拦截  只有 toString()被拦截了  咋回事呢？它也不符合切点表达式的要求啊  看下面的解释吧
        // 你被拦截了：方法名为：hello 参数为--[]
        // test.SpringAopApi$Demo@643b1d11
        System.out.println(demo.toString());
    }

    interface IDemo {
        void hello();
    }

    static class DemoImpl implements IDemo {
        public void hello() {
            System.out.println("demo say hello~~");
        }
    }

}
